package site.wetsion.galio.sdk.filter.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.filter.GenericFilterBean;
import site.wetsion.galio.sdk.common.GalioClientDetailsProperties;
import site.wetsion.galio.sdk.common.OauthClientContext;
import site.wetsion.galio.sdk.common.UserDetails;
import site.wetsion.galio.sdk.handler.DefaultUrlAccessHandler;
import site.wetsion.galio.sdk.handler.DefaultUrlDenyHandler;
import site.wetsion.galio.sdk.handler.UrlAccessHandler;
import site.wetsion.galio.sdk.handler.UrlDenyHandler;
import site.wetsion.galio.sdk.utils.AccessTokenHolderWrapper;
import site.wetsion.galio.sdk.utils.ResourceUtil;
import site.wetsion.galio.sdk.utils.UrlMatchUtil;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;
import java.util.regex.PatternSyntaxException;

/**
 * 默认提供的对URL进行权限校验拦截的过滤器
 *
 * @author wetsion
 * @version 1.0
 * @CLassName GalioDefaultUrlFilter
 * @date 2019/3/14 6:35 PM
 */
public class GalioDefaultUrlFilter extends GenericFilterBean {

    private final static Logger logger = LoggerFactory.getLogger(GalioDefaultUrlFilter.class);

    private GalioClientDetailsProperties galioClientDetailsProperties;

    private ResourceUtil resourceUtil;

    private UrlAccessHandler accessHandler = new DefaultUrlAccessHandler();

    private UrlDenyHandler denyHandler = new DefaultUrlDenyHandler();

    @Autowired
    OauthClientContext rmsOauthClientContext;
    @Autowired
    AccessTokenHolderWrapper accessTokenHolderWrapper;

    public GalioDefaultUrlFilter(GalioClientDetailsProperties galioClientDetailsProperties, ResourceUtil resourceUtil) {
        this.galioClientDetailsProperties = galioClientDetailsProperties;
        this.resourceUtil = resourceUtil;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        logger.debug("galio default url filter");
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;

        String currentUri = httpServletRequest.getRequestURI();

        // 查找配置的安全URL，如匹配则直接通过
        for (String sf : this.galioClientDetailsProperties.getSafetyUrl()) {
            if (UrlMatchUtil.checkMatch(sf, currentUri)) {
                chain.doFilter(request, response);
                return;
            }
        }

        logger.info("current uri: {}", currentUri);
        // 获取用户
        UserDetails userDetails = Objects.nonNull(rmsOauthClientContext.getAccessToken().getUserDetails()) ?
                rmsOauthClientContext.getAccessToken().getUserDetails() :
                accessTokenHolderWrapper.getTokenUser(rmsOauthClientContext.getAccessToken().getAccessToken());
        if (Objects.isNull(userDetails)) {
            logger.info("用户未登录授权，访问拒绝");
            denyHandler.onDenied(request, response);
            return;
        }

        String username = userDetails.getUsername();

        String urlResult = resourceUtil.getPlatformResources("url");

        // 若redis不存在系统的URL资源，则不拦截
        if (Objects.isNull(urlResult)) {
            chain.doFilter(request, response);
            return;
        }

        String userResult = resourceUtil.getPlatformUserResource(username);
        logger.debug("url result: {}", urlResult);
        try {
            JSONObject urlJobj = JSON.parseObject(urlResult);
            JSONArray urlResources = urlJobj.getJSONArray("items");

            JSONObject userResourceJobj = Objects.isNull(userResult) ? new JSONObject() : JSON.parseObject(userResult);
            JSONArray userResources = userResourceJobj.getJSONArray("items");

            if (Objects.isNull(urlResources) || urlResources.size() <= 0) {
                // 如果没有URL类型资源就放行
                chain.doFilter(request, response);
            } else {
                // 判断当前URL是否在该平台所设置的权限URL资源中
                boolean inPlatform  = false;
                for (int i = 0; i < urlResources.size(); i++) {
                    String content = urlResources.getJSONObject(i).getString("resourceContent");
                    boolean isMatch = UrlMatchUtil.checkMatch(content, currentUri);
                    if (isMatch) {
                        inPlatform = true;
                    }
                }
                // 判断当前url是否在该平台该用户所拥有的URL资源中
                boolean inUser = false;
                if ((!Objects.isNull(userResources)) && userResources.size() > 0) {
                    for (int j = 0; j < userResources.size(); j++) {
                        if ("url".equals(
                                userResources.getJSONObject(j).getString("resourceType")
                                        .toLowerCase())) {
                            String content = userResources.getJSONObject(j).getString("resourceContent");
                            boolean isMatchUser = UrlMatchUtil.checkMatch(content, currentUri);
                            if (isMatchUser) {
                                inUser = true;
                            }
                        }
                    }
                }

                if (!inPlatform) {
                    // 如果不在平台配置的URL资源中说明不需要拦截，放行
                    accessHandler.onAccess(request, response, chain);
                } else {
                    if (inUser) {
                        // 如果在平台配置的URL资源中也在用户资源中说明有权限，放行
                        accessHandler.onAccess(request, response, chain);
                    } else {
                        denyHandler.onDenied(request, response);
                        return;
                    }
                }
            }
        } catch (PatternSyntaxException pse) {
            logger.info("解析URL pattern 失败！:{}", pse.getMessage());
            denyHandler.onDenied(request, response);
        } catch (Exception e) {
            logger.info("获取url列表失败:{}", e.getMessage());
            denyHandler.onDenied(request, response);
            return;
        }
    }

    public void setAccessHandler(UrlAccessHandler accessHandler) {
        this.accessHandler = accessHandler;
    }

    public void setDenyHandler(UrlDenyHandler denyHandler) {
        this.denyHandler = denyHandler;
    }
}
